package Parser;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.TreeMap;

import org.supercsv.io.CsvMapWriter;
import org.supercsv.io.ICsvMapWriter;
import org.supercsv.prefs.CsvPreference;

public class CheckStyleParser {

	private final String startMetric = "<p class=\"p4\">";
	private final String endMetric = "</p>";
	private final String startValue = "<p class=\"p3\">";
	private final String endValue = "</p>";

	private final String MPATH = "NPath Complexity";
	private final String NCSS = "Non Commenting Source Statement";
	private final String CFOC = "Class Fan Out Complexity";
	private final String CDAC = "Class Data Abstraction Coupling";
	private final String MNFATHER = "Magic Numbers";
	private final String RC = "Return Count";
	private final String NC = "Naming Conventions";
	private final String JC = "Javadoc Comments";

	private final String MN = "'X' é um número mágico.";
	private final String CAD = "Class Data Abstraction Coupling is X (max allowed is X) classes X.";
	private final String CAFC = "Class Fan-Out Complexity is X (max allowed is X).";
	private final String CJ = "Comentário Javadoc de tipo não está presente na marca X.";
	private final String EMX = "Esperada a marca X para 'X'.";
	private final String ER = "Esperava uma marca @return.";
	private final String FMJ = "Falta o comentário Javadoc.";
	private final String MJU = "Marca Javadoc não utilizada.";
	private final String MD = "Marca X duplicada.";
	private final String MUX = "Marca X não utilizada por 'X'.";
	private final String NCSSC = "NCSS for this class is X (max allowed is X).";
	private final String NCSSF = "NCSS for this file is X (max allowed is X).";
	private final String NCSSM = "NCSS for this method is X (max allowed is X).";
	private final String NCX = "NPath Complexity is X (max allowed is X).";
	private final String NXC = "Nome 'X' deve condizer com o padrão 'X'.";
	private final String ONR = "O número de \"return\"s é X (máximo permitido é X).";
	private final String UT = "Unknown tag 'X'.";

	public TreeMap<String, TreeMap<String, Double>> extractMetricsPaths(
			String folderPath) throws Exception {
		TreeMap<String, TreeMap<String, Double>> metrics = new TreeMap<String, TreeMap<String, Double>>();
		File folder = new File(folderPath);
		File[] listOfFiles = folder.listFiles();

		for (int i = 0; i < listOfFiles.length; i++) {
			if (listOfFiles[i].isFile()) {
				if (listOfFiles[i].getName().endsWith(".html")) {
					metrics.put(
							listOfFiles[i].getName().replace(".html", ""),
							extractPackMetrics(listOfFiles[i].getAbsolutePath()));
				}
			}
		}

		return metrics;
	}

	private TreeMap<String, Double> extractPackMetrics(String path)
			throws Exception {
		TreeMap<String, Double> metrics = new TreeMap<String, Double>();
		File file = new File(path);
		FileReader fileReader = new FileReader(file);
		BufferedReader input = new BufferedReader(fileReader);
		String line = null;
		boolean isMetric = false;
		String metric = null;
		Double value = null;
		while ((line = input.readLine()) != null) {
			if (hasMetric(line)) {
				metric = getMetric(line);
				isMetric = true;
			} else if (hasValue(line) && isMetric) {
				value = getValue(line);
				isMetric = false;
				metrics.put(metric, value);
			}
		}
		return metrics;
	}

	private String getMetricGroup(String metric) {
		if (metric.equalsIgnoreCase(NCX)) {
			return NC;
		} else if (metric.equalsIgnoreCase(NCSSC)
				|| metric.equalsIgnoreCase(NCSSF)
				|| metric.equalsIgnoreCase(NCSSM)) {
			return NCSS;
		} else if (metric.equalsIgnoreCase(CAFC)) {
			return CFOC;
		} else if (metric.equalsIgnoreCase(CAD)) {
			return CDAC;
		} else if (metric.equalsIgnoreCase(MN)) {
			return MNFATHER;
		} else if (metric.equalsIgnoreCase(ONR)) {
			return RC;
		} else if (metric.equalsIgnoreCase(NXC)) {
			return NC;
		} else {
			return JC;
		}
	}

	private TreeMap<String, Double> simplifyMetrics(
			TreeMap<String, Double> metrics) {
		TreeMap<String, Double> simplifiedMetrics = new TreeMap<String, Double>();
		final String[] headerMetrics = new String[] { "Package", MPATH, NCSS,
				CFOC, CDAC, MNFATHER, RC, NC, JC };
		for (String metric : headerMetrics) {
			simplifiedMetrics.put(metric, 0.0);
		}
		for (String metric : metrics.keySet()) {
			simplifiedMetrics.put(
					getMetricGroup(metric),
					simplifiedMetrics.get(getMetricGroup(metric))
							+ metrics.get(metric));
		}
		return simplifiedMetrics;
	}

	private String getMetric(String line) throws Exception {
		if (!hasMetric(line)) {
			throw new Exception("No has metric!");
		}
		int start = line.indexOf(startMetric) + startMetric.length();
		int end = line.indexOf(endMetric);
		return line.substring(start, end);
	}

	private Double getValue(String line) throws Exception {
		if (!hasValue(line)) {
			throw new Exception("No has value!");
		}
		int start = line.indexOf(startValue) + startValue.length();
		int end = line.indexOf(endValue);
		return Double.parseDouble(line.substring(start, end));
	}

	private boolean hasMetric(String line) {
		return line.contains(startMetric);
	}

	private boolean hasValue(String line) {
		return line.contains(startValue);
	}

	public void writeMetrics(TreeMap<String, TreeMap<String, Double>> packs,
			String path) throws IOException {
		File file = new File(path);
		file.createNewFile();
		FileWriter fileWriter = new FileWriter(file.getAbsolutePath());
		ICsvMapWriter writer = new CsvMapWriter(fileWriter,
				CsvPreference.EXCEL_NORTH_EUROPE_PREFERENCE);
		final String[] headerMetrics = new String[] { "Package", MPATH, NCSS,
				CFOC, CDAC, MNFATHER, RC, NC, JC };
		writer.writeHeader(headerMetrics);

		for (String pack : packs.keySet()) {
			HashMap<String, ? super Object> data = new HashMap<String, Object>();
			data.put(headerMetrics[0], pack);
			TreeMap<String, Double> auxMetrics = simplifyMetrics(packs
					.get(pack));
			for (int i = 1; i < headerMetrics.length; i++) {
				if (auxMetrics.get(headerMetrics[i]) == null) {
					data.put(headerMetrics[i], "0");
				} else {
					data.put(headerMetrics[i], auxMetrics.get(headerMetrics[i])
							.toString());
				}
			}
			writer.write(data, headerMetrics);
		}
		writer.close();
	}

	public static void main(String[] args) {
		CheckStyleParser mp = new CheckStyleParser();
		try {
			mp.writeMetrics(
					mp.extractMetricsPaths("Files/CheckStyle/ExtractedFiles/HtmlOnly"),
					"Files/CheckStyle/GeneratedFiles/ResultCheckStyle.csv");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
